How to use Git

December 28, 2024

Git 是一款十分好用的分布式版本控制工具,作为一名开发者,无论你喜不喜欢它,你都不能离开它,也不能不学习它。

Git

Git下载安装、环境配置网上教程非常详细,出门左转,请自学,本文档不再介绍。

需要指明的是,GitHub不等于Git。GitHub是一个拥有很多仓库的在线网站,它的本体是一个Git服务器,这个Git服务器上存放着开发者们开发的各种项目。开发者们可以通过版本控制工具(如Git、SVN等)来使用GitHub上的各种项目。Git是一款分布式版本控制工具,我们可以使用Git来对项目进行管理,也可以通过它来使用GitHub上的各种项目。

从零开始使用Git

Git下载、安装、环境配置完成后,本章节介绍GitHub的使用、Git管理文件。

GitHub的使用

GitHub有两种常用的使用场景,一是从GitHub上下载项目到本地(以便于自己学习该项目或者在该项目的基础上做二次开发),二是把本地项目上传到GitHub(如果你没有自己的Git服务器的话)。本节先介绍如何从GitHub上下载项目,再介绍如何把本地项目上传到GitHub

如何从GitHub上下载项目

把一个项目从GitHub上下载到本地,采用以下的步骤:

  • 首先在本地计算机上创建一个目录文件用来保存从GitHub上下载下来的项目

    例如:作者想把他感兴趣的项目保存到这个文件夹(C:\Users\chenqijun\Desktop\Files\study)

  • 进行下面的操作:右键单击XX目录 -> 选择Open Git Bash Here打开

    windows11系统可能是:右键单击XX目录 -> 显示更多选项 -> Open Git Bash Here

    本例是右键单击study目录,选择Open Git Bash Here打开,然后按下面的步骤输入指令

  • 打开你感兴趣的项目所在仓库的GitHub网页,点击页面里的按钮Code -> HTTPS ->复制那串URL。

    这里以 https://github.com/chenxulin/git-practice 为例,点击页面里的按钮Code -> HTTPS ->复制那串URL(本例复制 https://github.com/chenxulin/git-practice.git )。

  • 在已经打开的Open Git Bash Here终端界面输入指令git clone ,克隆你感兴趣的项目。

    输入 git clone https://github.com/chenxulin/git-practice.git 即可把GitHub上的项目克隆到准备好的目录中。(有两种clone方式,使用HTTPS和SSH clone都可以,作者初学的时候使用的是HTTPS方式clone,故只介绍HTTPS来进行clone。SSH clone 方式有它的优点,想用SSH clone请自学。)

    Cloning into 'git-practice'...
    remote: Enumerating objects: 3, done.
    remote: Counting objects: 100% (3/3), done.
    remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0 (from 0)
    Receiving objects: 100% (3/3), done.

    终端界面如上,就说明已经把该项目从GitHub上克隆到本地目录中了,打开本地你准备好的目录即可看到该项目。

  • 克隆好后就可以使用开发工具(如IDEA、VS Code等)对下载的项目进行学习或者二次开发了。

  • 如果远端仓库的内容将来更新了,本地仓库可以使用git pull指令进行更新。

如何把本地项目上传到GitHub

把一个本地项目上传到自己的GitHub上,采用以下步骤:

  • 首先需要建立一个GitHub远端仓库,进入你的GitHub主页 -> 找到并点击按钮New -> 输入必填字段仓库名(Repository name) ->拉到页面最下面点击Create repository ,其他选项使用默认设置。这样就建立好一个名叫XX的GitHub仓库了。

    注:也可以不用默认设置,自己进行配置。每个选项有什么功能请自学。

  • 找到本地项目所在的那个文件夹,右键单击该文件夹,打开Open Git Bash Here终端界面,执行下面的操作。

    以C:\Users\chenqijun\Desktop\Files\study\git-practice-upload为例,即右键单击git-practice-upload,打开Open Git Bash Here终端界面,然后进行操作。

1.初始化仓库:输入 git init 指令后回车,初始化本地仓库,便于后续进行仓库管理
2.项目文件放入暂存区:输入 git add --all 指令后回车
3.暂存区的文件放入本地仓库:输入 git commit -m '这里写你想写的注释'
4.建立本地仓库与GitHub仓库的连接:输入 git remote add origin <你自己创建的仓库URL>
 (例:git remote add orgin https://github.com/chenxulin/git-practice.git)
5.把本地项目提交到GitHub上:输入 git push -u orgin master

依次按顺序完成以上步骤,把一个本地项目上传到你准备好的GitHub仓库中了

学会了下载别人项目和上传自己的项目,Git和GitHub的初步使用你已经学会了。现在,你已经是一名合格的Ctrl C + Ctrl V开发者了。

最后是必不可少(有时可以少)的胡言乱语时刻,我想说的是:千里之行,始于CV


Git管理文件(以Windows系统为例)

git提交到本地仓库
  • 对项目开始进行版本控制管理

    git init   // 初始化仓库指令

    这条指令实质上就是在项目所在文件夹里建立了一个.git的目录文件,Git版本控制就是依靠.git目录进行的。在对整个项目进行版本控制时,无论哪个文件或目录被删除了都能够找回来,但如果.git目录被删除了就没办法找回来了。

    .git文件默认被windows系统隐藏了,看不见是正常的,也可以把它显示出来(打开我的电脑 -> 点查看 -> 点显示 ->点击勾选隐藏的项目)。

  • 将某个文件或者目录提交至暂存区

git add 文件名   // 例如:git add hello.md 就是将hello.md文件放入暂存区
git add 目录名   // 例如:git add static 就是将static目录下的所有文件放入暂存区
git add *.后缀名 // 例如:git add *.html 就是将此目录下的所有以html结尾的文件放入暂存区

// Git 2.x后,下面git add --all和git add .用法是一样的。古老的版本的区别请自学
git add --all   // 将所有文件和文件夹加入暂存区
git add .       // 将所有文件和文件夹加入暂存区

注:空目录是无法加入到暂存区的。

以上是一些基本用法,设想一种特别的情况,如果你用git add 把某个文件加入暂存区,但还未commit到本地仓库,这时你改动了你add的文件,新手可能会直接commit,但这样是错误的,你需要重新git add这个文件,再commit。

  • 将暂存区的文件或目录提交(commit)到本地仓库

    git commit -m '注释'  // 将暂存区的文件或者目录全部送到本地仓库

    git commit -m '注释' 只是把暂存区的文件或者目录送到了本地仓库,那些还未通过git add命令送入暂存区的文件并不会被提交到本地仓库。一次commit会产生一条提交记录,git可以通过这些记录来进行回溯。

    注释是必要的,不加注释是没法commit的。进行注释可以让其他人知道这些文件进行了什么样的改动。注释内容要求简洁,清晰,有逻辑。

    并不是必须每次git add xxx之后都使用一次git commit -m '注释'指令立即提交,可以git add xxx然后又跑去开发别的文件,开发好后又使用git add xxx把新开发的文件加入暂存区,然后使用git commit '注释'一起提交。

    那么,究竟什么时候commit呢?
    一般来说:
    	1.完成某一个任务后:大到开发完一整个系统,小到完成某个小功能。
    	2.下班的时候:虽然可能任务还没完成,但至少先commit今天的进度。
    	3.你想什么时候提交就什么时候提交。

    从项目管理的角度看,第三种方式不是一个好的方式,因为程序世界总是充斥着条理,有个性往往会造成混乱。那么,我为什么要写上这种commit方式?答:我想写我就写。(我commit后,哪管它洪水滔天)

现在有必要对上述内容做一个总结,Git对一个项目进行版本控制时,被管理的项目分为工作目录、暂存区、本地仓库,必须先把工作目录添加(git add xxx)到暂存区,再将暂存区的文件提交(git commit -m '注释')到本地仓库。


git命令拾遗
  • 查看当前状态:
git status  // 查看当前状态

这条指令十分有用,比如查看暂存区有哪些文件未加到暂存区,哪些文件未提交等。

  • 查看当前目录有哪些文件
ls -al   // 查看当前目录下有什么文件
  • 使用git mv命令修改文件名
git mv 文件名1 文件名2  // 将某文件改名
// 例如:将hello.md文件改名成world.md,改动会被加入暂存区
git mv hello.md world.md

git删除文件与找回文件
  • rm命令
rm 文件名.后缀名   // 删除xx文件,但改动未加入暂存区
rm -r 目录名      // 删除xx 目录,但改动未加入暂存区
  • 使用git rm命令删除文件
git rm 文件名.后缀名   // 删除xx文件,并将改动加入暂存区
git rm -r 目录名      // 删除此目录下的所有文件,并将改动加入暂存区  
// 删除工作目录中的hello.md文件,并将这个改动加入暂存区,但并未commit
例如:git rm hello.md 
// 删除工作目录中的src目录下的所有文件,并将这个改动加入暂存区,但并未commit
例如:git rm -r src
  • 让git不再跟踪某文件
// --cached参数,不删除文件,只是让git不再跟踪该文件,且改动已放入到暂存区
git rm xxx --cached  

// 可以使用 git restore --staged <file>来取消放入暂存区
// 再用一次 git restore <flie>即可放回工作目录或者用 git checkout xxx指令也行
  • 使用git checkout找回删除的文件
// 文件已经删除,但此改动未用git add加入暂存区
git checkout 文件名.后缀名   // 把删除的xx文件放回工作目录
git checkout .             // 将删除的所有文件放回工作目录
// 文件已经删除,且改动已加入暂存区,但未commit

// 把删除的xx文件的改动撤销,再使用git checkout命令把删除的文件放回工作目录
git restore --staged 文件名.后缀名 
// 把删除的xx目录的改动撤销,再使用git checkout命令把删除的目录及目录下的文件放回工作目录
git restore --staged 目录名
// 把删除的所有文件的改动撤销,再使用git checkout命令把删除的所有文件放回工作目录
git restore --staged .
// commit记录的回退,用 git reset指令,见commit记录那一节的内容
// 文件已经删除,且改动已加入暂存区,并且已经提交

commit记录

查询commit记录
  • 查看commit记录的常用指令

    git log     // 查看完整commit记录
    git log --oneline // 精简版commit,一行一条commit记录
    git log --graph  // 有点好看的完整commit记录
    git log --oneline --graph // 既精简又好看的一行commit记录
    
    注:按q退出commit日志记录

    commit记录中包括:一串十六进制数、作者(Author)、时间(Date)、注释。例如:

    * commit 841458cebfb2023501574637d2bf8696e2948097 (HEAD -> upload, upload/upload)
    | Author: chenxulin <1011468693@qq.com>
    | Date:   Sun Dec 29 20:32:21 2024 +0800
    |
    |     test src/test3.txt

    这串十六进制数姑且看做这条记录的唯一标识好了,虽然可能并不唯一,但不唯一的几率极小。因为不影响使用,如果你对它感兴趣,请自学。

  • 按开发者名查询commit记录

    git log --oneline --author='xxx' // 查询某位开发者的提交记录
    
    例如:git log --oneline --author='chenxulin' 指令
    终端上的输出如下:
    841458c (HEAD -> upload, upload/upload) test src/test3.txt
    7914301 (upload/master, origin/master, origin/HEAD, master) test add directory
    75e78e8 first commit
    
    当然不同的提交记录有不同的输出,这里只是举例用。
  • 查找某一时间段的commit记录

    // 找出今天从上午9点到上午12点之间所有人的commit
    git log --oneline --since='9am' --until='12am'
    // 找出从2021年后,每天上午9点到上午12点之间所有人的commit
    git log --oneline --since='9am' --until='12am' --after='2021'
    
    例如:作者在终端上输入
    git log --oneline --since='13pm' --until='20pm' --after='2023'
    终端上会显示:
    7914301 (upload/master, origin/master, origin/HEAD, master) test add directory
    75e78e8 first commit
  • 查询某个具体文件的commit记录

git log 文件名.后缀名     // 查看此文件的commit记录
git log -p 文件名.后缀名  // 查看此文件每次commit做了什么改动
查询某行代码是谁写的
git blame 文件名.后缀名         // 找出此文件的每一行代码是谁写的
git blame -L A,B 文件名.后缀名  // 找出此文件第A行到第B行的代码是谁写的
修改commit记录的注释
// 将最近的一次commit的注释用新的注释进行覆盖
git commit --amend -m '新的注释'
追加文件到最近一次commit中
// 先用 git add <flie>将其加入暂存区
// 将<file>追加到最近一次commit中,且不改变其已提交的注释
   git commit --amend --no-edit 
注:像这样改动commit内容的操作,尽量不要用在已经push出去的commit上
擦除掉某条commit记录
git reset xxx // 前往指定标识的commit
// 例如前往标识为85e7e30的commit
git reset 85e7e30
// 前往master/HEAD/标识符的第前N次commit
git reset master^
git reset master^^
git reset master~3
git reset HEAD^
git reset e12d8ef^
// 参数: --mixed, --soft, --hard
--mixed commit拆出来的文件留在工作目录,不放回暂存区
--soft  commit拆出来的文件留在工作目录,放回暂存区
--hard  commit拆出来的文件,工作目录和暂存区都删除
例:git reset 85e7e30 --hard

// 查看引用日志reflog
git reflog  // 可以查到那些reset后消失的commit的标识

// 用git revert指令来删除最后一次提交
git revert HEAD --no-edit   // 增加一次commit,这次commit的作用是删除上一次commit。
注:这样做的好处是可以保留所有的commit记录,即上一次commit记录还在,只是上一次commit的内容被取消了,坏处是会增加一次commit记录,是commit记录变多,维护起来变得冗长。

多分支协作开发

在实际项目的开发过程中,个人的力量总是有限的,一个大型的项目往往需要多位开发者协作完成,为了使得每位开发者提交代码的过程不至于相互发生冲突而产生混乱,每一位开发者都会在属于自己的分支上进行开发,最后把各自开发的结果合并起来,这就是多分支协作开发。

当前所在分支
git branch  // 输出当前在这个项目中有哪些分支

Git会默认设置一个名为master的分支,用*表示当前正在哪个分支上
更改分支名称
git branch -m 原分支名 新分支名

// 例如更改empire分支的名称改为paper-tiger
git branch -m empire paper-tiger
新建分支
git branch 分支名  

// 例如:新建一个名为cat的分支
git branch cat 
分支切换
git checkout 分支名

// 切换当前分支到cat分支上
git checkout cat

注:已经改动但未commit,切换分支后,也能将改动直接提交到新分支上。
删除分支
git branch -d 分支名
git branch -D 分支名

// 例如:删除名叫cat的分支
git branch -d cat
// 若cat分支上有内容还未合并,-d参数无法将分支删除,改用-D参数即可将其强制删除
git branch -D cat

注:没有什么分支是不能删除的,包括默认的master分支也是能删除的(master分支只是默认的分支,没有其他特别之处)。
注: 当前在分支A上,不能删除分支A,必须先切换到分支B上,才能对A分支进行删除操作。
合并分支
git checkout 分支名   // 切换到目标分支
git merge 分支名      // 把分支名代表的分支合并到当前分支上
git merge 分支名 --no-ff // 额外多出一个commit记录这次合并结果

// 把cat分支合并到master分支上
git checkout master  // 先把分支切换回master分支
git merge cat        // 把cat分支合并到master分支上
另一种合并分支的方法
// 以给定的分支为基准,将当前分支合并到指定分支上
git rebase 分支名

// 例:当前在cat分支上,将cat分支合并到dog分支上
git rebase dog

注:使用rebase的好处是不想merge合并那样会产生额外合并专用的commit,坏处是rebase合并不如merge合并直观。
注:对于还未push出去的commit,可以使用rebase分支来整理commit。但对于公共commit,尽量不要使用rebase合并。

思考一下:
	1.除此之外,rebase合并和merge合并的区别在哪里?
	2.如何取消merge合并和rebase合并。
挽救分支
挽救未合并的分支的具体方法以下面的操作为例:
	假设cat有两个commit还未提交
	// 强行删除未合并的分支cat,删除后得到一个标识号b174a5a
	git branch -D cat  // 会得到一个cat当前指向的commit的标识号b174a5a
	// 找回这个commit,新建一个分支指向这个标识号b174a5a
	git branch new_cat b174a5a
	这样就找回了刚刚未合并的分支
	
注:如果刚刚删除的分支指向的commit的标识号忘记了,则用git reflog指令找回,reflog默认会保留30天。
回到过去
回到过去的某个commit,从那个commit处新建一个分支
git branch 分支名 标识号

例如,在commit标识号为657fce7的commit处开一个名为bird的分支
git branch bird 657fce7
git checkout bird   // 切换到刚刚创建的分支bird上

标签

轻量标签(lightweight tag)
git tag 标签名 commit标识号

// 给标识号为51d54ff的commit添加一个名为big_cat的轻量标签
git tag big_cat 51d54ff

// 注:如果只使用git tag 标签名 ,但未指定commit标识号,则将会把标签贴在当前所在的commit上
有附注的标签(annotated tag)
// -a参数就是指的是创建有附注的标签, -m指的是需要在后面添加注释
git tag 标签名 commit标识号 -a -m "注释"

// 例如:给标识号为51d54ff的commit添加一个名为big_cat的带附注的标签
git tag big_cat 51d54ff -a -m 'Big Cats are comming!'

注:有附注的标签主要用作软件版本号,轻量标签则是用于个人使用或者简单标记
注:有附注标签的好处是可以知道更多关于这张标签的信息,而轻量标签的信息量较少。
查看标签的信息
git show 标签名   // 查看标签信息

// 例如查看big_cat标签的信息
git show big_cat

注:轻量标签只有标签指向的那个commit的信息,有附注的标签多了一些信息,包括谁在什么时候贴了这张标签等。
删除标签
不管哪一种标签,其本质都像是一张贴纸,撕掉一张贴纸并不会造成commit或文档不见,只是把这张贴纸撕掉而已。

git tag -d 标签名

// 例如:删除名为big_cat的标签
git tag -d big_cat

总结

断断续续写了半个月,总的来说,写的不怎么样,不满意。原因大概有两点,

一,最开始没做好构思,只顾着学完记录下来。

二,初学时如雾里看花,对总体内容不太看得清。

写到后面才考虑到应当有场景+用法+实例,才对全部内容有一个大概的认识,但为时已晚。

后面复习Git或者深入学习Git的时候应对此文档进行重新梳理。

以上内容即为Git的基本用法,进阶用法请自学。

2025.1.11 晚


Profile picture

Written by chenqijun